from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from typing import Sequence, List

from emi.util import utils


class BaseEnum(Enum):
    pass

class OrderType(BaseEnum):
    """
    Order type.
    """
    LIMIT = "限价"
    MARKET = "市价"
    STOP = "STOP"
    FAK = "FAK"
    FOK = "FOK"

class OpType(BaseEnum):
    """
    操作类型
    """
    UNKONW = "未知"

    WIN = "盈利"   ##按预期的操作方式下单，如果顺利成交，则是盈利操作

    LOSS = "止损"  ##被动止损操作


class Direction(BaseEnum):
    """
    Direction of order/trade/position.
    """
    LONG = "多"
    SHORT = "空"



class Offset(BaseEnum):
    """
    Offset of order/trade.
    """
    NONE = ""
    OPEN = "开"
    CLOSE = "平"
    CLOSETODAY = "平今"
    CLOSEYESTERDAY = "平昨"



class Status(BaseEnum):
    """
    Order status.
    """
    SUBMITTING = "提交中"
    NOTTRADED = "未成交"
    PARTTRADED = "部分成交"
    ALLTRADED = "全部成交"
    CANCELLED = "已撤销"
    REJECTED = "拒单"

# @dataclass
# class RequestOrder:
#     """
#     请求订单
#     """
#     id:str
#     create_time:datetime
#     symbol: str
#     direction: Direction
#     type: OrderType
#     volume: float = 0     ##
#     frozen: float = 0  #冻结资金,也就是请求资金： 一般的，fronzen > price * volume,因为还的付佣金
#     price: float = 0  ## 请求价格


@dataclass
class RequestOrder:
    """
    请求订单
    """
    id : str
    symbol: str
    price: float
    volume: float = 0    ##
    type: OrderType = OrderType.LIMIT
    offset:Offset = Offset.NONE
    direction: Direction = Direction.LONG
    msg:str = None  ## 备注信息
    op_type:OpType = OpType.UNKONW
    source:any = None
    immediately:bool = False   ## True表示马上交易，不要挂单交易

@dataclass
class OrderData:
    """
    订单状态
    """
    symbol: str
    offset: Offset
    type: OrderType
    direction: Direction
    price: float
    volume: float  # 请求仓位
    id: str = None
    volume_traded: float = 0  # 成交仓位
    frozen_money: float = 0  # 属于冻结资金,用来开仓的资金,得考虑佣金情况。
    need_open_money: float = 0  # 需要的开仓资金（成交所需要的资金）
    status: Status = None
    create_time: datetime = None
    update_time: datetime = None
    description: str = ""  # 描述
    msg: str = None  # 备注信息
    op_type: OpType = OpType.UNKONW
    source: any = None  ## 不需要保存。
    immediately:bool = False   ## True表示马上交易，不要挂单交易

    def __post_init__(self):
        if self.id is None:
            self.id = f"_OrderData_{utils.next_uuid()}"
        if self.create_time is None:
            self.create_time = datetime.now()
        if self.update_time is None:
            self.update_time = self.create_time

    def is_finished(self)->bool:
        return self.status == Status.CANCELLED \
               or  self.status == Status.NOTTRADED \
               or self.status == Status.ALLTRADED or self.status == Status.REJECTED

@dataclass
class TradeData:
    """
    成交记录
    Trade data contains information of a fill of an order. One order
    can have several trade fills.
    """

    symbol: str
    orderid: str
    direction: Direction
    offset: Offset
    day_token:int   ## 交易日期令牌序号， 用于计算两个成交单之间的持有天数。
    time: datetime = None
    price: float = 0.0    ##每股成交价
    volume: int = 0   ## 成交量
    commission:float = 0.0  ## 佣金费用
    trade_money:float = 0.0  ## 成交金额
    op_type:OpType = OpType.UNKONW
    msg:str = None ## 备注信息
    source:any = None   ## 注意：用于传递数据，不会保存到数据库


@dataclass
class AccountData:

    balance: float
    available:float

    @property
    def float_blance(self) -> float:
        """
        账号的持有市场浮动资金。
        """
        return self.balance - self.available

@dataclass
class PositionData:

    """
    持有订单。
    """
    symbol: str
    direction: Direction
    update:datetime = None
    create:datetime = None

    volume_frozen: float = 0  ## 被冻结的持仓
    volume_available: float = 0  ## 可用仓位

    price_in:float = 0 ## 买入价格，多次买入会摊薄价格
    duration:int = 0  ## 持有天数

    price_cur:float = 0   ## 每股现价

    source:any = None  ## 上次买入订单带过来的参数

    def __post_init__(self):
        if self.create is None:
            self.create = datetime.now()
        if self.update is None:
            self.update = self.create


    # def __setattr__(self, key, value):
    #     super().__setattr__(key,value)
    #     if key.startswith("price_cur"):
    #         print(f"PositionData['{self.symbol}'].price_cur = {value}")

    @property
    def volume(self) -> float:
        """
        总仓位
        """
        return self.volume_available + self.volume_frozen

    # @property
    # def pnl(self):
    #     """
    #     盈亏金额
    #     """
    #     return self.balance - self.volume * self.price_in
    #
    # @property
    # def pnl_radio(self):
    #     """
    #     盈亏金额比例
    #     """
    #     return self.pnl / (self.volume * self.price_in)


@dataclass
class DailyResult:

    time: datetime
    day_token:int   ## 交易日期令牌序号， 用于计算两个成交单之间的持有天数。

    balance: float = 0  ##当天市值
    commission:float = 0  ## 当天产生的佣金费
    balance_hold:float = 0  ## 持有筹码市值

    tradeDatas:List[TradeData] = None  ## 当天成交记录

    def __post_init__(self):
        if self.tradeDatas is None:
            self.tradeDatas = []